package wlsAgent;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.naming.Context;

public class StateCollector {

	private MBeanServerConnection connection;

	private JMXConnector connector;

	private static final ObjectName service;

	// Initializing the object name for DomainRuntimeServiceMBean
	// so it can be used throughout the class.

	private Map mBeanMap = new HashMap();	
	
	private Map jvmRuntimeMap = new HashMap();

	private Map serverRuntimeMap = new HashMap();

	private Map threadPoolRuntimeMap = new HashMap();

	private Map jdbcDataSourceRuntimeMap = new HashMap();

	private ObjectName[] serverRT;

	static {

		try {
			service = new ObjectName(
					"com.bea:Name=DomainRuntimeService,Type=weblogic.management.mbeanservers.domainruntime.DomainRuntimeServiceMBean");
		} catch (MalformedObjectNameException e) {
			throw new AssertionError(e.getMessage());
		}
	}

	/*
	 * Initialize connection to the Domain Runtime MBean Server
	 */
	public void initConnection(String hostname, String portString,
			String username, String password) throws Exception {

		if (hostname == null)
			hostname = "127.0.0.1";
		if (portString == null)
			portString = "7001";
		if (username == null)
			username = "weblogic";
		if (password == null)
			password = "weblogic";

		String protocol = "t3";
		Integer portInteger = Integer.valueOf(portString);
		int port = portInteger.intValue();
		String jndiroot = "/jndi/";
		String mserver = "weblogic.management.mbeanservers.domainruntime";
		JMXServiceURL serviceURL = new JMXServiceURL(protocol, hostname, port,
				jndiroot + mserver);
		Hashtable h = new Hashtable();
		h.put(Context.SECURITY_PRINCIPAL, username);
		h.put(Context.SECURITY_CREDENTIALS, password);
		h.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES,
				"weblogic.management.remote");
		h.put("jmx.remote.x.request.waiting.timeout", new Long(10000));
		connector = JMXConnectorFactory.connect(serviceURL, h);
		connection = connector.getMBeanServerConnection();
		serverRT = getServerRuntimes();
		System.out.println("Got " + serverRT.length + "wls instances...\n");
	}

	/*
	 * Print an array of ServerRuntimeMBeans. This MBean is the root of the
	 * runtime MBean hierarchy, and each server in the domain hosts its own
	 * instance.
	 */
	public ObjectName[] getServerRuntimes() throws Exception {
		return (ObjectName[]) connection
				.getAttribute(service, "ServerRuntimes");
	}

	/*
	 * Generate JVMRuntime
	 */
	private ObjectName getJVMRuntime(ObjectName obj) throws Exception {
		ObjectName JVMRmb = (ObjectName) connection.getAttribute(obj,
				"JVMRuntime");
		return JVMRmb;
	}

	/*
	 * Get ThreadPoolRuntime
	 */
	private ObjectName getThreadPoolRuntime(ObjectName obj) throws Exception {
		ObjectName threadPoolRmb = (ObjectName) connection.getAttribute(obj,
				"ThreadPoolRuntime");
		return threadPoolRmb;
	}

	/*
	 * Generate JDBCDataSourceRuntime
	 */
	private ObjectName getJDBCDatasourceRuntime(ObjectName obj)
			throws Exception {
		ObjectName JVMRmb = (ObjectName) connection.getAttribute(obj,
				"JDBCDataSourceRuntime");
		return JVMRmb;
	}

	/*
	 * Get Mbean object by name and parent MBean
	 */
	private ObjectName getRuntimeMbean(ObjectName parentMbeanObj,
			String sonMbeanObj) throws Exception {
		if (connection != null) {
			ObjectName rmb = (ObjectName) connection.getAttribute(
					parentMbeanObj, sonMbeanObj);
			return rmb;
		} else
			return null;
	}

	/*
	 * Iterate through given Mbean and get wanted attribute values
	 */
	public Map getMBeanInfoMap(Vector<String> attrVec, String mBeanTpe)
			throws Exception {
		return null;
	}

	/*
	 * Iterate through JVMRuntimeMBeans and get the name and state
	 */
	public Map getJVMInfo(ObjectName on) throws Exception {
		this.jvmRuntimeMap.clear();
		this.jvmRuntimeMap.put("OSName", connection.getAttribute(
				getJVMRuntime(on), "OSName"));
		this.jvmRuntimeMap.put("OSVersion", connection.getAttribute(
				getJVMRuntime(on), "OSVersion"));
		this.jvmRuntimeMap.put("JavaVersion", connection.getAttribute(
				getJVMRuntime(on), "JavaVersion"));
		this.jvmRuntimeMap.put("JavaVendor", connection.getAttribute(
				getJVMRuntime(on), "JavaVendor"));
		this.jvmRuntimeMap.put("JavaVMVendor", connection.getAttribute(
				getJVMRuntime(on), "JavaVMVendor"));
		this.jvmRuntimeMap.put("HeapFreeCurrent", connection.getAttribute(
				getJVMRuntime(on), "HeapFreeCurrent"));
		this.jvmRuntimeMap.put("HeapSizeCurrent", connection.getAttribute(
				getJVMRuntime(on), "HeapSizeCurrent"));
		this.jvmRuntimeMap.put("HeapSizeMax", connection.getAttribute(
				getJVMRuntime(on), "HeapSizeMax"));
		this.jvmRuntimeMap.put("HeapFreePercent", connection.getAttribute(
				getJVMRuntime(on), "HeapFreePercent"));
		return this.jvmRuntimeMap;
	}

	/*
	 * Iterate through ServerRuntimeMBeans and get the name and state
	 */
	public Map getServerInfo(ObjectName on) throws Exception {
		this.serverRuntimeMap.clear();
		this.serverRuntimeMap.put("ActivationTime", connection.getAttribute(on,
				"ActivationTime"));
		this.serverRuntimeMap
				.put("State", connection.getAttribute(on, "State"));
		this.serverRuntimeMap.put("HealthState", connection.getAttribute(on,
				"HealthState"));
		this.serverRuntimeMap.put("Name", connection.getAttribute(on, "Name"));
		this.serverRuntimeMap.put("OpenSocketsCurrentCount", connection
				.getAttribute(on, "OpenSocketsCurrentCount"));
		this.serverRuntimeMap.put("ServerClasspath", connection.getAttribute(
				on, "ServerClasspath"));
		this.serverRuntimeMap.put("WeblogicVersion", connection.getAttribute(
				on, "WeblogicVersion"));
		this.serverRuntimeMap.put("ListenAddress", connection.getAttribute(on,
				"ListenAddress"));
		this.serverRuntimeMap.put("ListenPort", connection.getAttribute(on,
				"ListenPort"));
		return this.serverRuntimeMap;
	}

	/*
	 * Iterate through threadPoolRuntimeMBeans and get the name and state
	 */
	public Map getThreadPoolInfo(ObjectName on) throws Exception {
		this.threadPoolRuntimeMap.clear();
		this.threadPoolRuntimeMap.put("ExecuteThreadIdleCount", connection
				.getAttribute(getThreadPoolRuntime(on),
						"ExecuteThreadIdleCount"));
		this.threadPoolRuntimeMap.put("CompletedRequestCount",
				connection.getAttribute(getThreadPoolRuntime(on),
						"CompletedRequestCount"));
		this.threadPoolRuntimeMap.put("ExecuteThreadTotalCount", connection
				.getAttribute(getThreadPoolRuntime(on),
						"ExecuteThreadTotalCount"));
		this.threadPoolRuntimeMap.put("PendingUserRequestCount", connection
				.getAttribute(getThreadPoolRuntime(on),
						"PendingUserRequestCount"));
		this.threadPoolRuntimeMap.put("QueueLength", connection.getAttribute(
				getThreadPoolRuntime(on), "QueueLength"));
		this.threadPoolRuntimeMap.put("StandbyThreadCount", connection
				.getAttribute(getThreadPoolRuntime(on), "StandbyThreadCount"));
		this.threadPoolRuntimeMap.put("Throughput", connection.getAttribute(
				getThreadPoolRuntime(on), "Throughput"));
		return this.threadPoolRuntimeMap;
	}

	/*
	 * Iterate through JDBCDatasourceRuntimeMBeans and get the name and state
	 */
	public Map getJDBCDatasourceInfo(ObjectName on) throws Exception {
		this.jdbcDataSourceRuntimeMap.clear();
		this.jdbcDataSourceRuntimeMap.put("ActiveConnectionsCurrentCount",
				connection.getAttribute(this.getJDBCDatasourceRuntime(on),
						"ActiveConnectionsCurrentCount"));
		this.jdbcDataSourceRuntimeMap.put("ConnectionsTotalCount ", connection
				.getAttribute(getJDBCDatasourceRuntime(on),
						"ConnectionsTotalCount "));
		this.jdbcDataSourceRuntimeMap.put("CurrCapacity", connection
				.getAttribute(getJDBCDatasourceRuntime(on), "CurrCapacity"));
		this.jdbcDataSourceRuntimeMap.put("FailedReserveRequestCount",
				connection.getAttribute(getJDBCDatasourceRuntime(on),
						"FailedReserveRequestCount"));
		this.jdbcDataSourceRuntimeMap.put("LeakedConnectionCount", connection
				.getAttribute(getJDBCDatasourceRuntime(on),
						"LeakedConnectionCount"));
		this.jdbcDataSourceRuntimeMap.put("Name", connection.getAttribute(
				getJDBCDatasourceRuntime(on), "Name"));
		this.jdbcDataSourceRuntimeMap.put("Properties", connection
				.getAttribute(getJDBCDatasourceRuntime(on), "Properties"));
		return this.jdbcDataSourceRuntimeMap;
	}

	public void closeCollector() throws Exception {
		connector.close();
	}

	public static void main(String[] args) throws Exception {
		// String hostname = args[0];
		// String portString = args[1];
		// String username = args[2];
		// String password = args[3];

		String hostname = "127.0.0.1";
		String portString = "7001";
		String username = "weblogic";
		String password = "weblogic";

		StateCollector sc = new StateCollector();
		sc.initConnection(hostname, portString, username, password);

		int length = (int) sc.serverRT.length;
		for (int i = 0; i < length; i++) {
			sc.getJVMInfo(sc.serverRT[i]);
			System.out.println(sc.jvmRuntimeMap.toString() + "\n");

			sc.getServerInfo(sc.serverRT[i]);
			System.out.println(sc.serverRuntimeMap.toString() + "\n");

			sc.getThreadPoolInfo(sc.serverRT[i]);
			System.out.println(sc.threadPoolRuntimeMap.toString() + "\n");
		}

		sc.connector.close();
	}
}